package com.aznest.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.cache.*;

import java.time.Duration;

/**
 * 自定义 RedisCacheManager配置。
 */
@Slf4j
public class CustomRedisCacheManager extends RedisCacheManager {

    /**
     * 项目名
     */
    private final static String SPRING_APPLICATION_NAME = "aznest";

    /**
     * 自定义缓存参数的TTL分隔符
     * 示例：value|cacheNames = “keyName#ttlOfSecond”。
     */
    private static final String CUSTOM_TTL_SEPARATOR = "#";

    public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
        super(cacheWriter, defaultCacheConfiguration);
    }

    /**
     * @param name        must not be {@literal null}. 业务 Cache注解的value|cacheNames
     * @param cacheConfig can be {@literal null}.
     * @return
     */
    @Override
    protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
        Duration ttl = getTtlByCustomName(name);
        if (ttl == null) {
            // 如果自定义 TTL为空，则设置全局 TTL为7天。
            ttl = Duration.ofDays(7);
        }
        /**
         * Cache缓存配置
         */
        cacheConfig = cacheConfig
                .computePrefixWith(CUSTOM_CACHE_KEY_PREFIX) // 设置缓存key
                .entryTtl(ttl)  // 设置缓存的过期时间，查询不会更新过期时间
        ;
        return super.createRedisCache(name, cacheConfig);
    }

    /**
     * Cache 默认的 RedisKey的格式为（@Cacheable注解上的信息）： value|cacheNames::key。
     * 自定义需求：
     * 1、key前缀分隔符:: 不习惯，换成:前缀分隔符。
     * 2、在 Cache相关注解 key的生成规则上，添加全局缓存 key的前缀。
     */
    private static final CacheKeyPrefix CUSTOM_CACHE_KEY_PREFIX = cacheName -> {
        // 过滤掉自定义的 TTL分隔符
        String cacheName0 = cacheName.split(CUSTOM_TTL_SEPARATOR)[0];
        return SPRING_APPLICATION_NAME + ":" + cacheName0 + ":";
    };


    /**
     * 根据 TTL分隔符拆分字符串，并进行过期时间 TTL的解析
     *
     * @param name 业务 Cache注解的value|cacheNames
     * @return
     */
    private Duration getTtlByCustomName(String name) {
        if (StringUtils.isBlank(name)) {
            return null;
        }
        /**
         * 根据 TTL分隔符拆分字符串，并进行过期时间 TTL的解析
         * 数组元素0 = 缓存的名称
         * 数组元素1 = 缓存过期时间TTL
         */
        String[] cacheParams = name.split(CUSTOM_TTL_SEPARATOR);
        if (cacheParams.length > 1) {
            // 如果 TTL解析异常或者小于等于0，则返回null;
            Long ttl = null;
            try {
                ttl = Long.parseLong(cacheParams[1]);
            } catch (NumberFormatException e) {
                log.debug(" CacheManager 解析自定义 TTL异常，e.getMessage = {}", e.getMessage());
            }
            if (ttl != null && ttl > 0) {
                return Duration.ofSeconds(ttl);
            }
        }
        return null;
    }
}

